/**
 * @version		$Id: extensions.js 20 2011-01-13 17:50:15Z happy_noodle_boy $
 * @package		JCE
 * @copyright	Copyright (C) 2009 Ryan Demmer. All rights reserved.
 * @license		GNU/GPL
 * This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 */
(function($) {
    $.fn.ExtensionMapper = function(options) {
        this.each(function() {
            return $.ExtensionMapper.init(this, options);
        });
    }, 
	$.ExtensionMapper = {
        options: {},
        /**
         * Initilaise plugin
         * @param {Object} elements Select elements to process
         * @param {Object} options Options object
         */
        init: function(el, options) {
            var t = this, input, v;
            $.extend(this.options, options);
            
            var name = $(el).attr('name').replace(/\[\]/, '');
            
			input = document.createElement('input');
			v = $(el).val() || '';
			
            $(input).attr({
                name	: name,
                id		: $(el).attr('id'),
                value	: typeof(v) == 'string' ? v : v.join(';'),
				type 	: 'hidden'
            }).insertBefore(el);
			
			if ($(el).hasClass('create')) {
				$(input).addClass('create');
			}
			
			$(el).remove();
            el = input;
			
			input = document.createElement('input');
            // Create placeholder clone
			$(input).attr({
				type 		: 'text',
				'disabled'	: 'disabled',
				'value'		: el.value
			}).insertBefore(el);
			
            // hide element
			$(el).hide();
			
            var link = document.createElement('a');
            
            $(link).attr({
                href: '#'
            }).bind('click', function(e) {
                e.preventDefault();
				
				if (!this.mapper) {
					$(link).children('span').addClass('loader');
					
					this.mapper = t.buildMapper(el);
					
					$(this.mapper).hide().insertAfter(link).slideDown(450, function() {						
						$(link).children('span').removeClass('loader');
						// Show scroll buttons
						$('div.jce_extensions_list_box ul').each(function() {
							if(this.firstChild.offsetHeight * this.childNodes.length > this.parentNode.offsetHeight) {
								this.parentNode.nextSibling.style.visibility = 'visible';
							}
						});
					});
				} else {
					$(this.mapper).slideToggle(450);
				}
            }).html('<span class="jce_extensions_edit"></span>').insertAfter(el);
        },
        
        buildMapper: function(el) {
            var t = this, d = document;
            // Create container;
            var container = d.createElement('div');
            $(container).addClass('jce_extensions');
            
            // Create extension groups
            var groups = this.createGroups(el, container);           
            $(container).append(groups);
			
			var div = d.createElement('div');
			$(div).addClass('jce_extensions_group_add').appendTo(container);
			
			if ($(el).hasClass('create')) {
				var add = d.createElement('span');
				
				$(add).click(function() {
					var group = t.createGroup(el, container);
					$(group).hide().insertBefore(div).fadeIn('fast');
					
					t.createSortable(el, container, $(group).find('ul'));
					
				}).appendTo(div);
			}
            this.createSortable(el, container, $(container).find('ul'));
			
			return container;
        },
		
		createSortable : function(el, container, list) {
			var t = this;
			// Create sortable lists
            $(list).sortable({
                connectWith	: '.jce_extensions_list',
                placeholder	: 'sortable-highlight',
                update: function(event, ui) {
                    if (!ui.sender) 
                        return;
                    
                    t.showScroll($(ui.item).parent(), ['bottom']);
                    t.showScroll($(ui.sender), ['top', 'bottom']);
                    
                    t.setValues(el, container);
                }
            }).disableSelection();
		},
        
        /**
         * Create a single list group
         * @param {Object} input
         * @param {Object} container
         * @param {Object} values
         */
        createGroup: function(input, container, values) {
            var t = this, d = document;
            if (!values) {
                values = ['custom', 'custom'];
            }
            // Create group container
            var box 	= d.createElement('div');
			// Create title container
			var title 	= d.createElement('div');			
            // Create scroll buttons
            var scrolltop = d.createElement('div');
            var scrollbottom = d.createElement('div');
            // Create group title
            var group = d.createElement('span');
            // Create list box
            var list = d.createElement('div');
            // Create list
            var ul = d.createElement('ul');
            // Checkbox
            var check = d.createElement('span');
            
            // Add class to group container
            $(box).addClass('jce_extensions_box');
			
			$(title).appendTo(box);

			// add 0 margin
			$(ul).css('margin', 0);
            
            // Create input element if custom
            if (values[0] == 'custom') {
                var custom = d.createElement('input');
                $(custom).attr({
                    type: 'text',
                    size: 8
                }).change(function() {
                    if (this.value == '') 
                        return;
                    
                    $(this).parent().addClass(this.value.toLowerCase()).attr('title', this.value.toLowerCase());
                }).appendTo(group);
				
				var remove = d.createElement('span');
				$(remove).addClass('jce_extensions_group_remove').click(function() {
					$(box).fadeOut('fast', function() {
						$(box).remove();
					});
				}).appendTo(title);
				
                // Set title html
            } else {
				 // Add checkbox			
	            $(check).addClass('checkbox').addClass(function() {
	                return values[0].charAt(0) == '-' ? '' : 'checked';
	            }).click(function() {
	                if ($(this).hasClass('checked')) {
	                    $(group).attr('title', '-' + values[0]);
	                    $(this).removeClass('checked');
	                } else {
	                    $(group).attr('title', values[0]);
	                    $(this).addClass('checked');
	                }
	                // Trigger serialization
	                t.setValues(input, container);
	            }).appendTo(title);
				
				values[0] = values[0].replace(/[\W]/g, '');

				// Set html as title case
                $(group).html(values[0].charAt(0).toUpperCase() + values[0].substr(1));
            }

			// Create group title
            $(group).addClass('jce_extensions_group').attr('title', values[0]).addClass(values[0]).appendTo(title);
			
			var div = d.createElement('div');
			$(div).addClass('jce_extensions_list_add').appendTo(box);
			var add = d.createElement('span');
			$(add).click(function() {
				$(ul).prepend(t.createItem(input, container, 'custom')).hide().fadeIn('fast');
			}).appendTo(div);
            
            // Add scroll top button, click event and append
            $(scrolltop).addClass('jce_extensions_scroll_top').appendTo(box).click(function() {
                t.scrollTo('top', ul);
            });
            // Add list box class and append
            $(list).addClass('jce_extensions_list_box').appendTo(box);
            // Add list class and append
            $(ul).addClass('jce_extensions_list').appendTo(list);
            // Add scroll bottom button, click event and append
            $(scrollbottom).addClass('jce_extensions_scroll_bottom').appendTo(box).click(function() {
                t.scrollTo('bottom', ul);
            });

            // Split value by comma to get individual file extensions and build list elements
            $.each(values[1].split(','), function() {
                $(ul).append(t.createItem(input, container, this));
            });

            // Return container div
            return box;
        },
		
		createItem : function(input, container, value) {
			var t = this, d = document, v = value.replace(/[^a-z0-9]/, '');
            //  Create elements
            var li = d.createElement('li'), title = d.createElement('span'), check = d.createElement('span');
            // Add clases and append
            $(li).addClass('file ' + v);
            $(title).addClass('jce_extensions_title').appendTo(li);
            
            // Create input element if custom
            if (value == 'custom') {
                var custom = d.createElement('input');
                $(custom).attr({
                    type: 'text',
                    size: 6
                }).change(function() {
                    if (this.value == '') {
                        $(this).removeClass('duplicate');
                        $(li).removeClass(function() {
                            return this.className.replace(/(file|custom)/, '');
                        });
                        
                        return;
                    }
                    
                    // Remove non alphabet characters
                    this.value = this.value.replace(/[^a-z0-9]/, '');
                    // Check for existing extension
                    if (new RegExp(new RegExp('[=,]' + this.value + '[,;]')).test($(input).val())) {
                        $(this).addClass('duplicate');
                        $(li).addClass('duplicate');
                    } else {
                        $(this).removeClass('duplicate');
                        $(li).removeClass(function() {
                            return this.className.replace(/(file|custom)/, '');
                        }).addClass(this.value);
                        
                        // Trigger serialization
                        if (this.value != '') {
                            t.setValues(input, container);
                        }
                    }
                }).appendTo(title);
				
				var remove = d.createElement('span');
				$(remove).addClass('jce_extensions_list_remove').click(function() {
					$(li).fadeOut('fast', function() {
						$(li).remove();
						
						// Trigger serialization
                        if (custom.value != '') {
                            t.setValues(input, container);
                        }
					});
				}).appendTo(li);
                // Set title html
            } else {
                $(title).attr('title', value);
                title.innerHTML = v;
				
				// Add checkboxes			
	            $(check).addClass('checkbox').addClass(function() {
	                return value.charAt(0) == '-' ? '' : 'checked';
	            }).click(function() {
	                if ($(this).hasClass('checked')) {
	                    $(title).attr('title', '-' + v);
	                    $(this).removeClass('checked');
	                } else {
	                    $(title).attr('title', v);
	                    $(this).addClass('checked');
	                }
	                // Trigger serialization
	                t.setValues(input, container);
	            }).appendTo(li);
            }

			return li;
		},
		
        /**
         * Create Groups
         * @param {Object} input
         * @param {Object} container
         */
        createGroups: function(input, container) {
            var t = this, groups = [], v = input.value;
            // Split into groups
            $.each(v.split(';'), function() {
                var group = t.createGroup(input, container, this.split('='));
                groups.push(group);
            });
            return groups;
        },
        
        /**
         * Show Scroll button
         * @param {Object} el UL element
         * @param {Array} dir Direction
         */
        showScroll: function(el, dir) {
            var p = $(el).parent(), m = parseFloat($(el).css('margin-top'));
            
            function check(el, p, dir) {
                if (dir == 'top') {
                    return parseFloat(m) == 0;
                } else {
					if (m == 0) {
                        var c = $(el).children();
                        return $(c).first().outerHeight() * c.length < $(p).outerHeight();
                    } else {
                        return (m + $(el).outerHeight()) < $(p).outerHeight();
                    }
                }
            }
            var scroll = (dir == 'top') ? p.prev() : p.next();
            $.each(dir, function(n, s) {
				if (check(el, p, s)) {
                    scroll.css('visibility', 'hidden');
                } else {
                    scroll.css('visibility', 'visible');
                }
            });
        },
        /**
         * Scroll list
         * @param {Object} dir Direction to scroll in
         * @param {Object} ul List element
         */
        scrollTo: function(dir, ul) {
            var t = this, p = $(ul).parent(), mt = parseFloat($(ul).css('margin-top')), x = ul.firstChild.offsetHeight, v = mt - x, inv;
            
            if (dir == 'top') {
                v = mt + x;
                
                v = v + 1;
                
                if (mt == 0 || v > 0) 
                    return;
            } else {
                v = v - 1;
            }
            
            inv = (dir == 'top') ? p.next() : p.prev();
            
            $(ul).animate({
                'marginTop': v
            }, 500, function() {
                $(inv).css('visibility', 'visible');
                t.showScroll(ul, [dir]);
            });
        },
		
        /**
         * Serialize lists and pass value to input element
         * @param {Object} input
         * @param {Object} container
         */
        setValues: function(input, container) {
            var v = input.value, groups = [], title;
            
            // Iterate through child divs
            $(container).children().each(function() {
				$(this).find('span.jce_extensions_group:first').each(function() {
					var n = this, c = n.firstChild;
					if (c && c.nodeName == 'INPUT') {
						title = c.value;
					} else {
						title = n.title;
					}
				});
                
                if (title) {
                    var list = [], v, title = title.toLowerCase();
                    $(this).find('li span').each(function() {
                        var n = this, c = n.firstChild;
						if (c && c.nodeName == 'INPUT') {
                        	v = c.value;
                        } else {
							v = $(n).attr('title');
						}
						if (v) {
							list.push(v);
						}
                    });
                    // Add list to group
                    groups.push(title + '=' + list.join(','));
                }
            });
            v = groups.join(';');
			
			v = v.replace(/([a-z]+)=;/g, '');
			
            input.value = v;
        }
    }
})(jQuery);
